SwiftData nested models crash upon trying to access nested data.

I am new to swift. This is my Item.swift.

import SwiftData

@Model
final class Item: Codable {
    var id: String
    var soundId: String
    var soundAppleId: String
    var soundType: String
    var type: String
    var authorId: String
    var text: String
    var createdAt: Date
    var actionsCount: Int
    var chainsCount: Int
    var rating: Int
    var loved: Bool
    var replay: Bool
    var heartedByUser: Bool
    @Relationship var author: Author?
    
    init(id: String, soundId: String, soundAppleId: String, soundType: String, type: String, authorId: String, text: String, createdAt: Date, actionsCount: Int, chainsCount: Int, ratings: Int, loved: Bool, replay: Bool, heartedByUser: Bool, author: Author) {
        self.id = id
        self.soundId = soundId
        self.soundAppleId = soundAppleId
        self.soundType = soundType
        self.type = type
        self.authorId = authorId
        self.text = text
        self.createdAt = createdAt
        self.actionsCount = actionsCount
        self.chainsCount = chainsCount
        self.rating = ratings
        self.loved = loved
        self.replay = replay
        self.heartedByUser = heartedByUser
        self.author = author
    }

    private enum CodingKeys: String, CodingKey {
        case id
        case soundId = "sound_id"
        case soundAppleId = "sound_apple_id"
        case soundType = "sound_type"
        case type
        case authorId = "author_id"
        case text
        case createdAt = "created_at"
        case actionsCount = "actions_count"
        case chainsCount = "chains_count"
        case rating
        case loved
        case replay
        case heartedByUser
        case author
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        soundId = try container.decode(String.self, forKey: .soundId)
        soundAppleId = try container.decode(String.self, forKey: .soundAppleId)
        soundType = try container.decode(String.self, forKey: .soundType)
        type = try container.decode(String.self, forKey: .type)
        authorId = try container.decode(String.self, forKey: .authorId)
        text = try container.decode(String.self, forKey: .text)

        let dateString = try container.decode(String.self, forKey: .createdAt)
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
        if let date = formatter.date(from: dateString) {
            createdAt = date
        } else {
            throw DecodingError.dataCorruptedError(forKey: .createdAt,
                                                   in: container,
                                                   debugDescription: "Date string does not match format expected by formatter.")
        }
        
        actionsCount = try container.decode(Int.self, forKey: .actionsCount)
        chainsCount = try container.decode(Int.self, forKey: .chainsCount)
        rating = try container.decode(Int.self, forKey: .rating)
        loved = try container.decode(Bool.self, forKey: .loved)
        replay = try container.decode(Bool.self, forKey: .replay)
        heartedByUser = try container.decode(Bool.self, forKey: .heartedByUser)
        author = try container.decode(Author.self, forKey: .author)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        
        try container.encode(id, forKey: .id)
        try container.encode(soundId, forKey: .soundId)
        try container.encode(soundAppleId, forKey: .soundAppleId)
        try container.encode(soundType, forKey: .soundType)
        try container.encode(type, forKey: .type)
        try container.encode(authorId, forKey: .authorId)
        try container.encode(text, forKey: .text)
        
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        let dateString = formatter.string(from: createdAt)
        try container.encode(dateString, forKey: .createdAt)
        
        try container.encode(actionsCount, forKey: .actionsCount)
        try container.encode(chainsCount, forKey: .chainsCount)
        try container.encode(rating, forKey: .rating)
        try container.encode(loved, forKey: .loved)
        try container.encode(replay, forKey: .replay)
        try container.encode(heartedByUser, forKey: .heartedByUser)
        
        try container.encode(author, forKey: .author)
    }

}


@Model
final class Author: Codable {
    var id: String
    var image: URL
    var username: String
    var bio: String?

    init(id: String, image: URL, username: String, bio: String?) {
        self.id = id
        self.image = image
        self.username = username
        self.bio = bio
    }

    private enum CodingKeys: String, CodingKey {
        case id
        case image
        case username
        case bio
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        image = try container.decode(URL.self, forKey: .image)
        username = try container.decode(String.self, forKey: .username)
        bio = try container.decodeIfPresent(String.self, forKey: .bio)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(image, forKey: .image)
        try container.encode(username, forKey: .username)
        try container.encodeIfPresent(bio, forKey: .bio)
    }
}

In my ItemView when I try to access something inside author, Swift preview crashes.


Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   SwiftData                     	       0x1cb459e90 0x1cb3d3000 + 552592
1   SwiftData                     	       0x1cb45ba7c 0x1cb3d3000 + 559740
2   SwiftData                     	       0x1cb45e5f8 0x1cb3d3000 + 570872
3   SwiftData                     	       0x1cb4190e4 0x1cb3d3000 + 286948
4   audition                      	       0x100b436e0 Item.author.getter + 320 (@__swiftmacro_8audition4ItemC6author18_PersistedPropertyfMa_.swift:9)
5   ContentView.1.preview-thunk.dylib	       0x105f23a20 closure #1 in closure #1 in closure #1 in closure #1 in ItemCard.__preview__body.getter + 820 (ContentView.swift:89)
6   SwiftUI                       	       0x1cba41308 0x1cb47b000 + 6054664
7   ContentView.1.preview-thunk.dylib	       0x105f22ee4 closure #1 in closure #1 in closure #1 in ItemCard.__preview__body.getter + 472 (ContentView.swift:84)
8   SwiftUI                       	       0x1cc2e6c40 0x1cb47b000 + 15121472
9   ContentView.1.preview-thunk.dylib	       0x105f228b8 closure #1 in closure #1 in ItemCard.__preview__body.getter + 388 (ContentView.swift:83)
...
Post not yet marked as solved Up vote post of coratype Down vote post of coratype
143 views
  • i gave up on this and removed SwiftData from my project since SwiftData itself is new and barely documented

  • Got the same issue here. The funniest thing is that I have a very similar model with the error one works pretty well. It looks like SwiftData for now is really buggy and error-prone...

Add a Comment

Replies

Not sure if this helps, but I just figured out that if you don't do modelContext.insert before you access its nested model property (like the Author? in your case), the app will crash with a SwiftData access error (SwiftData error code is "0x1cb459e90") even you wrap the code block with a do-try-catch.